package com.zzj.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zzj.base.Result;
import com.zzj.base.ResultCode;
import com.zzj.service.RedisService;
import com.zzj.utils.JWTUtil;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

import static com.zzj.base.ResultCode.NO_LOGGED_IN;

@Log4j2
@RefreshScope
@Component
public class JWTAuthFilter implements GlobalFilter {

    @Value("#{'${no-filter.prefix-path}'.split(',')}")
    private List<String> prefixPaths;

   @Resource
   private RedisService redisService;

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {


        String url = exchange.getRequest().getURI().getPath();
        log.info("访问地址: {}", url);

        // 放行访问
        if (isPathMatched(url, prefixPaths)) {
            return chain.filter(exchange);
        }

        // 检查是否有 token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null) {
            return writeResponse(exchange, new Result(NO_LOGGED_IN));
        }

        // 验证 JWT token 是否有效
        boolean verifyResult = JWTUtil.verify(token);
        if (!verifyResult) {
            return writeResponse(exchange, new Result<>(ResultCode.TOKEN_EXPIRED));
        }

        // 检查 token 是否在 Redis 黑名单中
        boolean inBlackList = redisService.isInBlackList(token);
        if (inBlackList) {
            return writeResponse(exchange, new Result(ResultCode.NO_LOGGED_IN));
        }

        return chain.filter(exchange);
    }

    private boolean isPathMatched(String path, List<String> patterns) {
        return patterns.stream().anyMatch(path::startsWith);
    }

    private Mono<Void> writeResponse(ServerWebExchange exchange, Result result) throws JsonProcessingException {
        ServerHttpResponse response = exchange.getResponse();
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

        DataBufferFactory bufferFactory = response.bufferFactory();
        ObjectMapper objectMapper = new ObjectMapper();
        DataBuffer buffer = bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
        return response.writeWith(Mono.just(buffer));
    }
}
